package uit.nfcmenu.activity;

import java.util.ArrayList;

import uit.nfcmenu.R;
import uit.nfcmenu.db.model.IDataChangeHandler;
import uit.nfcmenu.db.model.ItemModel;
import uit.nfcmenu.db.model.MenuModel;
import uit.nfcmenu.db.model.OrderModel;
import uit.nfcmenu.manager.ItemManager;
import uit.nfcmenu.manager.MenuManager;
import uit.nfcmenu.manager.OrderManager;
import uit.nfcmenu.util.CommConstant;
import uit.nfcmenu.util.NetworkHelper;
import uit.nfcmenu.util.UiUtilities;
import uit.nfcmenu.util.Utilities;
import uit.nfcmenu.webservice.MyException;
import uit.nfcmenu.webservice.PreferenceHelper;
import uit.nfcmenu.webservice.WSMapping;
import android.app.Activity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.res.Resources;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Button;

public abstract class BaseActivity extends Activity implements IDataChangeHandler {
	static String tag = BaseActivity.class.getSimpleName();
	
	static final int SHOW_NOTHING = 1;
	static final int SHOW_MESSAGE_ON_TOAST = 2;
	static final int SHOW_MESSAGE_ON_DIALOG = 3;

	public static BaseActivity baseActivity;
	protected Context mContext;
	protected Resources mRes;
	
	private ProgressDialog mProgressDialog;
	private boolean mIsShowProgressBar;
	
	private static ArrayList<BaseActivity> mChildrenList;
	protected boolean isDataChangedOnView = true; 

	@Override
	protected void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		mContext = getActivityContext();
		mRes = mContext.getResources();
		baseActivity = this;
		mIsShowProgressBar = true;
		isDataChangedOnView = true; 
		
		getChildren().add((BaseActivity)mContext);
	}
	
	private ArrayList<BaseActivity> getChildren() {
		if (mChildrenList == null) {
			mChildrenList = new ArrayList<BaseActivity>();
		}
		return mChildrenList;
	}

	/**
	 * (Required) You must implement this method for each Child class which extends 
	 * from this class. Just implement it with "return this;" Then you can use 
	 * mContext instead "this" when programming inside that Child Activity. Just  
	 * easy for coding. If not, your mContext will be null, and your app will crash
	 */
	abstract protected Context getActivityContext();

	/**
	 * for common structure
	 */
	protected void initView() {
		ViewGroup topBarView = (ViewGroup) findViewById(R.id.topBar);
		if (mContext != null && topBarView != null) { // just check there are top_bar view in activity
//			Button btnRefresh = (Button) findViewById(R.id.btnRefresh);
			Button btnMenu = (Button) findViewById(R.id.btnMenu);
			Button btnOrderList = (Button) findViewById(R.id.btnOrderList);
			Button btnCookedList = (Button) findViewById(R.id.btnCookedList);
			Button btnLogout = (Button) findViewById(R.id.btnLogout);
			
//			btnRefresh.setVisibility(View.GONE);
			btnMenu.setVisibility(View.GONE);
			btnOrderList.setVisibility(View.GONE);
			btnCookedList.setVisibility(View.GONE);
			btnLogout.setVisibility(View.GONE);
			
			if (mContext instanceof WaiterMenuActivity) {
//				btnRefresh.setVisibility(View.VISIBLE);
				btnOrderList.setVisibility(View.VISIBLE);
				btnLogout.setVisibility(View.VISIBLE);
			} 
			else if (mContext instanceof WaiterItemActivity) {
				//btnRefresh.setVisibility(View.VISIBLE);
				btnOrderList.setVisibility(View.VISIBLE);
				btnLogout.setVisibility(View.VISIBLE);
			} 
			else if (mContext instanceof WaiterDetailActivity) {
//				btnRefresh.setVisibility(View.VISIBLE);
//				btnMenu.setVisibility(View.VISIBLE);
				btnOrderList.setVisibility(View.VISIBLE);
				btnLogout.setVisibility(View.VISIBLE);
			} 
			else if (mContext instanceof OrderActivity) {
//				btnRefresh.setVisibility(View.VISIBLE);
				btnLogout.setVisibility(View.VISIBLE);
			} 
//			else if (mContext instanceof WaiterOrderActivity) {
//				btnRefresh.setVisibility(View.VISIBLE);
//				btnMenu.setVisibility(View.VISIBLE);
//				btnLogout.setVisibility(View.VISIBLE);
//			} 
//			else if (mContext instanceof ChefOrderListActivity) {
//				btnRefresh.setVisibility(View.VISIBLE);
//				btnCookedList.setVisibility(View.VISIBLE);
//				btnLogout.setVisibility(View.VISIBLE);
//			} 
			else if (mContext instanceof ChefCookedListActivity) {
				btnOrderList.setVisibility(View.VISIBLE);
				btnLogout.setVisibility(View.VISIBLE);
			}  
		}
	}
	
	@Override
	public void onBackPressed() {
		if ((mContext instanceof OrderActivity && !CommConstant.isWaiter)
				|| mContext instanceof WaiterMenuActivity) {
			popMessage(R.string.mess_want_to_logout, 
					new DialogInterface.OnClickListener() {
						@Override
						public void onClick(DialogInterface dialog, int which) {
							new DoLogout().execute();
						}
					});
		} else {
			super.onBackPressed();
		}
	}
	
	// abstract protected void initData();
	// abstract protected void initListener();
	protected void changeLanguage(String language) {
		Utilities.changeLanguage(mContext, language);
	}
	
	protected void updateInView(Object... o) { }
	protected void recycle() { }

	@Override
	protected void onDestroy() {
		super.onDestroy();
		getChildren().remove((BaseActivity)mContext);
		baseActivity = null;
		recycle();
	}
	
	@Override
	protected void onPause() {
		super.onPause();
		getProgressDialog().dismiss();
	}

	@Override
	public void notifyDataChanged() { }
	
	/*
	 * Progress Dialog
	 */
	public boolean isProgressBarShown() {
		return mIsShowProgressBar;
	}

	public void setProgressBarShowable(boolean isShown) {
		mIsShowProgressBar = isShown;
	}

	private ProgressDialog getProgressDialog() {
		if (mProgressDialog == null) {
			mProgressDialog = new ProgressDialog(mContext);
		}
		return mProgressDialog;
	}

	protected void setProgressDialogMessage(String message) {
		getProgressDialog().setMessage(message);
	}

	protected void setProgressDialogMessage(int messId) {
		getProgressDialog().setMessage(
				(messId > 0) ? mRes.getString(messId) : "");
	}

	protected void showProgressDialog(String message) {
		Log.i(tag, "isShownProgressDialod="+(mIsShowProgressBar==true && !getProgressDialog().isShowing()));
		if (mIsShowProgressBar && !getProgressDialog().isShowing()) {
			setProgressDialogMessage(message);
			mProgressDialog.show();
		}
	}

	protected void showProgressDialog(int messId) {
		if (mIsShowProgressBar && !getProgressDialog().isShowing()) {
			setProgressDialogMessage(messId);
			mProgressDialog.show();
		}
	}
	
	/*
	 * Message
	 */

	protected void popMessage(int messId,
			android.content.DialogInterface.OnClickListener onClickListener) {
		UiUtilities.popAlert2Choose(mContext, R.string.message, messId, 
				R.string.yes, onClickListener, R.string.cancel, null);
	}
	
	/*
	 * Default listener
	 */
	
//	public void onBtnRefresh_click(View v) {
//		Log.i(tag, "onBtnRefresh_click()");
//	}
	
	public void onBtnMenu_click(View v) {
		Log.i(tag, "onBtnMenu_click()");
		launchMenuActivity();
	}
	
	public void onBtnOrderList_click(View v) {
		Log.i(tag, "onBtnOrderList_click()");
		launchOrderListActivity();
	}
	
	public void onBtnCookedList_click(View v) {
		Log.i(tag, "onBtnCookedList_click()");
		launchCookedListActivity();
	}

	public void onBtnLogout_click(View v) {
		Log.i(tag, "onBtnLogout_click()");
		popMessage(R.string.mess_want_to_logout, 
				new DialogInterface.OnClickListener() {
					@Override
					public void onClick(DialogInterface dialog, int which) {
						new DoLogout().execute();
					}
				});
	}
	
	/*
	 * Common methods for screen (Child Activity)
	 */

	protected void launchMenuActivity() {
		Intent intent = new Intent(mContext, WaiterMenuActivity.class);
		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		startActivity(intent);
	}

	protected void launchLoginActivity() {
		BackGroundSync.stopService();
		Intent intent = new Intent(mContext, LoginActivity.class);
		intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
		// TODO clear all activity on stack
		if (mChildrenList != null && mChildrenList.size() > 0) {
			for (BaseActivity child : mChildrenList){
				Log.e(tag, "finish child "+child.getLocalClassName());
				child.finish();
			}
		}
		startActivity(intent);
	}

	protected void launchOrderListActivity() {
//		Intent intent = new Intent(mContext, WaiterOrderActivity.class);
//		Intent intent = new Intent(mContext, ChefOrderActivity.class);
		Intent intent = new Intent(mContext, OrderActivity.class);
		startActivity(intent);
	}
	
//	protected void launchChefOrderListActivity() {
//		Intent intent = new Intent(mContext, ChefOrderListActivity.class);
//		startActivity(intent);
//	}
	
	private void launchCookedListActivity() {
		Intent intent = new Intent(mContext, ChefCookedListActivity.class);
		startActivity(intent);
	}

	/**
	 * 
	 * @param context
	 * @param runnable
	 * @param messShownOn
	 * SHOW_NOTHING: not show message, this action only on background
	 * SHOW_MESSAGE_ON_TOAST: show message on progressDialog, then show toast if without network
	 * SHOW_MESSAGE_ON_PROGRESS_DIALOG: show message on progressDialog, then show alert if without network
	 * @param messageId
	 */
	public static boolean doIfMeetNetworkOrShowFailStatus(Context context, 
			int messShownOn, Runnable runnable) {
		boolean isDialogShown = (messShownOn != SHOW_NOTHING);
		Log.i(tag, "isDialogShown="+isDialogShown);
		((BaseActivity) context).setProgressBarShowable(isDialogShown);
		if (NetworkHelper.checkNetworkStatus(context)) {
			runnable.run();
			return true;
		} else {
			if (messShownOn == SHOW_MESSAGE_ON_DIALOG) {
				UiUtilities.popupAlertMessage(context, R.string.message, 
						R.string.mess_offline, R.string.ok);
			} else if (messShownOn == SHOW_MESSAGE_ON_TOAST) {
				UiUtilities.makeShortToast(context, R.string.mess_offline);
			}
		}
		return false;
	}
	
	/*
	 * Contact DB
	 */

	protected void updateMenusFromServer() throws MyException {
		MenuManager.getInstance(mContext).updateMenus();
	}

	protected void updateItemsFromServer() throws MyException  {
		ItemManager.getInstance(mContext).updateItems();
	}

	protected ArrayList<MenuModel> getMenus() {
		return MenuManager.getInstance(mContext).getAllMenuInDB();
	}
	
	protected ArrayList<ItemModel> getItems() {
		return ItemManager.getInstance(mContext).getAllItems();
	}
	
	protected ArrayList<ItemModel> getItemsByMenu(MenuModel menu) {
		return ItemManager.getInstance(mContext).getItemsByMenu(menu.getId());
	}

	protected void updateOrders() throws MyException {
		OrderManager.getInstance(mContext).updateOrders();
	}

	protected ArrayList<ArrayList<ItemModel>> getItemsByMenus(
			ArrayList<MenuModel> menus) {
		ArrayList<ArrayList<ItemModel>> modelsList;
		modelsList = new ArrayList<ArrayList<ItemModel>>(menus.size());
		
		ArrayList<ItemModel> models = null;
		for (MenuModel menu : menus) {
			models = getItemsByMenu(menu);
			if (models != null) {
				modelsList.add(models);
			}
		}
		
		return modelsList;
	}
	
	protected ArrayList<OrderModel> getOrders() {
		Log.i(tag, "getOrders()");
		return OrderManager.getInstance(mContext).getOrdersInDB();
	}
	
	protected ArrayList<OrderModel> getOrders(String date) {
		Log.i(tag, "getOrders() date="+date);
		return OrderManager.getInstance(mContext).getOrdersInDB();
	}

	/*
	 * Async Tasks
	 */
	public void startAsyncTask(boolean isShowProgressBar, Runnable runInBg,
			Runnable runInPost) {
		new OwnAsyncTask(isShowProgressBar, runInBg, runInPost).execute();
	}

	protected class OwnAsyncTask extends AsyncTask<Void, Void, Void> {

		Runnable mRunInBg;
		Runnable mRunInPost;

		public OwnAsyncTask(boolean isShowProgressBar, Runnable runInBg,
				Runnable runInPost) {
			mRunInBg = runInBg;
			mRunInPost = runInPost;
			mIsShowProgressBar = isShowProgressBar;
		}

		@Override
		protected void onPreExecute() {
			super.onPreExecute();
			// Log.i(tag+":OwnAsyncTask", "onPreExecute()");

			if (mIsShowProgressBar) {
				getProgressDialog().show();
			}
		}

		@Override
		protected Void doInBackground(Void... params) {
			// Log.i(tag+":OwnAsyncTask", "doInBackground()");

			if (mRunInBg != null) {
				mRunInBg.run();
			}
			return null;
		}

		@Override
		protected void onPostExecute(Void result) {
			super.onPostExecute(result);
			// Log.i(tag+":OwnAsyncTask", "onPostExecute()");

			if (mIsShowProgressBar) {
				mProgressDialog.dismiss();
			}

			if (mRunInPost != null) {
				mRunInPost.run();
			}
		}
	}
	
	class DoLogout extends BaseLoader {

		@Override
		protected Integer doInBackground(Void... params) {
			// TODO test handle ws here
//			try {
//				Thread.sleep(4000);
//			} catch (InterruptedException e) {
//				e.printStackTrace();
//			}
			String username = PreferenceHelper.loadUsername(mContext);
			String deviceId = PreferenceHelper.loadDeviceId(mContext);
			if (WSMapping.logout(username, deviceId)) {
				return 1;
			} else {
				return 0;
			}

		}

		@Override
		protected void onPostExecute(Integer result) {
			super.onPostExecute(result);	
//			if (result == 1) {
				launchLoginActivity();
//			} else {
//				UiUtilities.popupAlertMessage(mContext, R.string.message,
//						R.string.mess_login_fail, R.string.ok);
//			}
		}
	}
	
	public class RunLoader extends Thread {
		BaseLoader loader;

		public RunLoader(BaseLoader load) {
			loader = load;
		}

		@Override
		public void run() {
			super.run();
			if (loader == null)
				return;

			if (BackGroundSync.getSyncStatus() == false) {
				loader.execute();
			} else {

				(new Handler()).post(new Runnable() {

					@Override
					public void run() {
						showProgressDialog("");
					}
				});
				while (BackGroundSync.getSyncStatus()) {
					try {
						sleep(1000);
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
				}
				loader.notShowDialog();
				loader.execute();
			}
		}
	}
	
	public class BaseLoader extends AsyncTask<Void, Void, Integer> {
//		 private static final String TAG = "BaseLoader";
		private boolean show = true;
		Boolean returnOrNot = false;

		public void notShowDialog() {
			show = false;
		}

		@Override
		protected void onPreExecute() {
			Log.i(tag, "isShownProgressDialod="+(show==true && isProgressBarShown()==true));
			if (show) {
				try {
					showProgressDialog("");
				} catch (Exception e) {
					// FIXME showProgressDialog Exception
					Log.e(tag, "showProgressDialog Exception", e);
				}
			}
			
			BackGroundSync.othersIsProgress();
			super.onPreExecute();
		}

		@Override
		protected Integer doInBackground(Void... params) {
			return -1;
		}

		@Override
		protected void onPostExecute(Integer result) {
			if (getProgressDialog() != null) {
				getProgressDialog().dismiss();
			}
			BackGroundSync.otherEndProgress();
		}
	}

	public class BaseSaver extends AsyncTask<Void, Void, Integer> {
	//	 private static final String tag = BaseSaver.class.getSimpleName();
	
		private boolean show = true;

		public void notShowDialog() {
			show = false;
		}

		@Override
		protected void onPreExecute() {
			if (show) {
				showProgressDialog("");
			}
			BackGroundSync.othersIsProgress();
			super.onPreExecute();
		}

		@Override
		protected Integer doInBackground(Void... params) {
			return null;
		}

		@Override
		protected void onPostExecute(Integer result) {
			if (getProgressDialog() != null) {
				getProgressDialog().dismiss();
			}
			BackGroundSync.otherEndProgress();
		}
	}

	@Override
	public void saveData() {
		Log.i(tag, "saveData()");
	}

	@Override
	public Context getContext() {
		return mContext;
	}
}
